﻿using System;
using System.Collections.Generic;
using System.Text;
using OpenTK;

namespace LasRendering
{
    public struct Matrix3x3
    {
        public float v11;
        public float v12;
        public float v13;
        public float v21;
        public float v22;
        public float v23;
        public float v31;
        public float v32;
        public float v33;

        public Matrix3x3(
            float m11, float m12, float m13,
            float m21, float m22, float m23,
            float m31, float m32, float m33)
        {
            v11 = m11;
            v12 = m12;
            v13 = m13;
            v21 = m21;
            v22 = m22;
            v23 = m23;
            v31 = m31;
            v32 = m32;
            v33 = m33;
        }

        public Vector3 this[int row]
        {
            get
            {
                switch (row)
                {
                    case 0: return new Vector3(v11, v12, v13);
                    case 1: return new Vector3(v21, v22, v23);
                    case 2: return new Vector3(v31, v32, v33);
                    default:
                        throw new ArgumentOutOfRangeException("row");
                }
            }
        }

        public float this[int row, int column]
        {
            get
            {
                switch (row)
                {
                    case 0:
                        switch (column)
                        {
                            case 0:
                                return v11;
                            case 1:
                                return v12;
                            case 2:
                                return v13;
                            default:
                                throw new ArgumentOutOfRangeException("column");
                        }
                    case 1:
                        switch (column)
                        {
                            case 0:
                                return v21;
                            case 1:
                                return v22;
                            case 2:
                                return v23;
                            default:
                                throw new ArgumentOutOfRangeException("column");
                        }
                    case 2:
                        switch (column)
                        {
                            case 0:
                                return v31;
                            case 1:
                                return v32;
                            case 2:
                                return v33;
                            default:
                                throw new ArgumentOutOfRangeException("column");
                        }
                    default:
                        throw new ArgumentOutOfRangeException("row");
                }
            }
        }

        public static Matrix3x3 operator +(Matrix3x3 m1, Matrix3x3 m2)
        {
            return new Matrix3x3(
                m1.v11 + m2.v11, m1.v12 + m2.v12, m1.v13 + m2.v13,
                m1.v21 + m2.v21, m1.v22 + m2.v22, m1.v23 + m2.v23,
                m1.v31 + m2.v31, m1.v32 + m2.v32, m1.v33 + m2.v33);
        }

        public static Matrix3x3 operator -(Matrix3x3 m1, Matrix3x3 m2)
        {
            return new Matrix3x3(
                m1.v11 - m2.v11, m1.v12 - m2.v12, m1.v13 - m2.v13,
                m1.v21 - m2.v21, m1.v22 - m2.v22, m1.v23 - m2.v23,
                m1.v31 - m2.v31, m1.v32 - m2.v32, m1.v33 - m2.v33);
        }

        public static Matrix3x3 operator *(Matrix3x3 m, float f)
        {
            return new Matrix3x3(
                m.v11 * f, m.v12 * f, m.v13 * f,
                m.v21 * f, m.v22 * f, m.v23 * f,
                m.v31 * f, m.v32 * f, m.v33 * f);
        }

        public static Vector3 operator *(Matrix3x3 m, Vector3 v)
        {
            return new Vector3(
                m.v11 * v.X + m.v12 * v.Y + m.v13 * v.Z,
                m.v21 * v.X + m.v22 * v.Y + m.v23 * v.Z,
                m.v31 * v.X + m.v32 * v.Y + m.v33 * v.Z);
        }

        public static Matrix3x3 operator /(Matrix3x3 m, float f)
        {
            return new Matrix3x3(
                m.v11 / f, m.v12 / f, m.v13 / f,
                m.v21 / f, m.v22 / f, m.v23 / f,
                m.v31 / f, m.v32 / f, m.v33 / f);
        }

        public static float det(Matrix3x3 m)
        {
            return m.v11 * m.v22 * m.v33 + m.v12 * m.v23 * m.v31 + m.v13 * m.v21 * m.v32 - m.v11 * m.v23 * m.v32 - m.v12 * m.v21 * m.v33 - m.v13 * m.v22 * m.v31;
        }

        public static Matrix3x3 I
        {
            get
            {
                return new Matrix3x3(1, 0, 0, 0, 1, 0, 0, 0, 1);
            }
        }
    }
}
